#pragma once
/**
 * @file Eventloop.hpp
 * @author 1102403684@qq.com
 * @brief 基于 epoll 的事件循环，支持事件处理和定时器处理
 *
 * 事件循环:
 * - 基于 epoll 进行事件监控与处理
 * - 基于 TimerWheel 进行定时任务管理
 *
 * 开放接口：
 * - start() 进行一次事件循环，处理所有活跃事件
 * - 定时器接口 `add_timer()`, `delay_timer()`, `cancel_timer()` 实现定时任务的管理
 *
 * @version 0.1
 * @date 2024-10-08
 *
 * @copyright Copyright (c) 2024
 *
 */

#include <vector>
#include <functional>
#include <sys/eventfd.h>
#include <mutex>
#include <thread>

#include "../common/logger.hpp"
#include "Poller.hpp"
#include "TimerWheel.hpp"

using Functor = std::function<void()>;

class EventLoop
{
private:
    static int create_eventfd();
    void read_eventfd();
    void wakeup_eventfd();

    bool is_in_loop() { return thread_id_ == std::this_thread::get_id(); }
    void run_all_tasks(); // 执行任务池中所有任务
public:
    EventLoop() : thread_id_(std::this_thread::get_id()),
                  efd_(create_eventfd()),
                  echannel_(new Channel(this, efd_)),
                  timer_wheel_(this)
    {
        echannel_->set_read_callback(std::bind(&EventLoop::read_eventfd, this));
        echannel_->enable_read_event();

        LOG_TRACE("echannel_ 初始化完毕 占用fd {}", echannel_->get_fd());
    }
    // 提供给定时器用的两个接口
    void run_in_loop(const Functor &task);
    void queue_in_loop(const Functor &task);

    // 这是提供给channel用的两个接口
    void update_event(Channel *channel) { poller_.update_event(channel); } // 添加/修改 描述符的事件监控
    void remove_event(Channel *channel) { poller_.remove_event(channel); } // 删除 描述符事件监控

    void add_timer(uint64_t id, uint32_t delay, const TaskFunc &task_func) { timer_wheel_.TimerAddInLoop(id, delay, task_func); }
    void delay_timer(uint64_t id) { timer_wheel_.TimerRefreshInLoop(id); }
    void cancel_timer(uint64_t id)
    {
        timer_wheel_.TimerCancelInLoop(id);
    }
    bool has_timer(uint64_t id) { return timer_wheel_.HasTimer(id); }
    void start();

private:
    std::thread::id thread_id_;
    Poller poller_;
    std::vector<Functor> tasks_;
    std::mutex mutex_;
    /*eventfd*/
    uint64_t efd_;                      // 必须在channel之前声明
    std::unique_ptr<Channel> echannel_; // 必须在efd之后声明

    TimerWheel timer_wheel_;
};

/*------------------ EventLoop implement----------------------*/

int EventLoop::create_eventfd()
{
    int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
    if (efd < 0)
    {
        LOG_ERROR("创建 eventfd 失败 已退出");
        abort();
    }
    return efd;
}
void EventLoop::read_eventfd()
{
    uint64_t res = 0;
    int ret = read(efd_, &res, sizeof(res));
    if (ret < 0)
    {
        if (errno == EINTR)
        {
            return;
        }
        LOG_ERROR("读取eventfd时出错 已退出");
        abort();
    }
}
void EventLoop::wakeup_eventfd()
{
    uint64_t val = 1;
    int ret = write(efd_, &val, sizeof(val));
    if (ret < 0)
    {
        if (errno == EINTR || errno == EAGAIN)
        {
            return;
        }
        LOG_ERROR("唤醒eventfd时出错 已退出");
        abort();
    }
}

void EventLoop::run_all_tasks()
{
    std::vector<Functor> tasks;
    {
        std::unique_lock<std::mutex> lock(mutex_);
        tasks_.swap(tasks);
    }

    for (auto &task : tasks)
    {
        task(); 
    }
}

void EventLoop::start()
{
    while (true)
    {
        // 1 取出活跃的事件
        std::vector<Channel *> actives;
        poller_.poll(&actives);
        // 2 处理活跃事件
        for (auto &channel : actives)
        {
            channel->handle_event();
        }

        // 3 统一执行io操作
        run_all_tasks();
    }
}

void EventLoop::run_in_loop(const Functor &task)
{
    if (is_in_loop())
    {
        task();
        return;
    }
    // 不是则压入任务队列
    queue_in_loop(task);
}

void EventLoop::queue_in_loop(const Functor &task)
{
    {
        std::unique_lock<std::mutex> lock(mutex_);
        tasks_.push_back(task);
    }
    // 唤醒可能因为没有事件就绪导致的epoll阻塞
    wakeup_eventfd();
}

/*---------------Channel中要依赖eventloop对底层的进行操作-------------*/

void Channel::remove_epoll()
{
    eventloop_->remove_event(this);
}

void Channel::update_epoll()
{
    eventloop_->update_event(this);
}

/*---------------TimerWheel中要依赖eventloop的进行操作-------------*/

void TimerWheel::TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &task_func)
{
    loop_->run_in_loop(std::bind(&TimerWheel::TimerAdd, this, id, delay, task_func));
}

void TimerWheel::TimerRefreshInLoop(uint64_t id)
{
    loop_->run_in_loop(std::bind(&TimerWheel::TimerRefresh, this, id));
}

void TimerWheel::TimerCancelInLoop(uint64_t id)
{
    loop_->run_in_loop(std::bind(&TimerWheel::TimerCancel, this, id));
}
